import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:crypto/crypto.dart';
import 'package:get/get.dart';

import 'dd_http.dart';
import 'dd_other.dart';
import 'dd_user_service.dart';

class DDLogHeaderKye {
  static const String logHeaderKyeData = "data";
  static const String logHeaderKyeLogType = "log_type";
  static const String logHeaderKyeSubtype = "subtype";
  static const String logHeaderKyeBehavior = "behavior";
  static const String logHeaderKyeDeviceId = "device-id";
  static const String logHeaderKyeAndroidId = "android_id";
  static const String logHeaderKyeUserId = "user_id";
  static const String logHeaderKyePkg = "pkg";
  static const String logHeaderKyeChnId = "chn_id";
  static const String logHeaderKyeVer = "ver";
  static const String logHeaderKyePlatform = "platform";
  static const String logHeaderKyeModel = "model";
  static const String logHeaderKyePVer = "p_ver";
  static const String logHeaderKyeLanId = "lan_id";
  static const String logHeaderKyeSecId = "sec_id";
  static const String logHeaderKyeUtmSource = "utm_source";
  static const String logHeaderKyeAfAdgroupId = "af_adgroup_id";
  static const String logHeaderKyeAfAdset = "af_adset";
  static const String logHeaderKyeAfAdsetId = "af_adset_id";
  static const String logHeaderKyeAfStatus = "af_status";
  static const String logHeaderKyeAfAgency = "af_agency";
  static const String logHeaderKyeAfChannel = "af_channel";
  static const String logHeaderKyeAfCampaign = "campaign";
  static const String logHeaderKyeAfCampaignId = "campaign_id";
  static const String logHeaderKyeCountry = "country";
  static const String logHeaderKyesysLan = "sys_lan";
}

class DDLogService {
  DDLogService._();

  static final DDLogService _instance = DDLogService._();

  factory DDLogService() {
    return _instance;
  }

  static const String _event = 'event';
  static const String _tm = 'tm';
  static const String _page = 'page';
  static const String _subPage = 'subPage';
  static const String _terPage = 'terPage';
  static const String _broadcasterId = 'broadcasterId';
  static const String _duration = 'duration';

  static String launcherId = "";

  static int serialId = 0;
  static const int limitSize = 20;

  final List<Map<String, dynamic>> cacheList = [];

  bool isWaitingForSend = false;

  void setLauncherId() {
    launcherId = md5
        .convert(utf8.encode(
            '${DateTime.now().millisecondsSinceEpoch}${DDAppInfo.getInstance().udid}'))
        .toString();
  }

  void ddGa({
    String? page,
    String? subPage,
    String? terPage,
    String? broadcasterId,
  }) {
    var map = <String, dynamic>{};

    if (page != null) {
      map[_page] = page;
    }
    if (subPage != null) {
      map[_subPage] = subPage;
    }
    if (terPage != null) {
      map[_terPage] = terPage;
    }
    if (broadcasterId != null) {
      map[_broadcasterId] = broadcasterId;
    }
    map[_duration] = 0;
    map[_event] = 'pv';
    map[_tm] = DateTime.now().millisecondsSinceEpoch;

    putLog(DDLogType.globalBehavior, map);
  }

  Map<String, dynamic> logEventData(String logType, String subType,
      String behavior, Map<String, dynamic>? event) {
    String platform = '';
    String model = '';
    if (Platform.isAndroid) {
      platform = 'Android';
      model = DDAppInfo.getInstance().machine;
    } else if (Platform.isIOS) {
      platform = 'iOS';
      model = DDAppInfo.getInstance().machine;
    }
    Map<String, dynamic> itemData = {};
    itemData[DDLogHeaderKye.logHeaderKyeData] = [event];
    itemData[DDLogHeaderKye.logHeaderKyeLogType] = 'event';
    itemData[DDLogHeaderKye.logHeaderKyeSubtype] = 'global_behavior';
    itemData[DDLogHeaderKye.logHeaderKyeBehavior] = 'event';
    itemData[DDLogHeaderKye.logHeaderKyeDeviceId] =
        DDAppInfo.getInstance().udid;
    itemData[DDLogHeaderKye.logHeaderKyeUserId] =
        Get.find<DDUserService>().authModel.userinfo?.userId ?? '';
    itemData[DDLogHeaderKye.logHeaderKyePkg] =
        DDAppInfo.getInstance().packageName;
    itemData[DDLogHeaderKye.logHeaderKyeChnId] = '';
    itemData[DDLogHeaderKye.logHeaderKyeVer] =
        DDAppInfo.getInstance().version ?? '';
    itemData[DDLogHeaderKye.logHeaderKyePlatform] = platform;
    itemData[DDLogHeaderKye.logHeaderKyeModel] = model;
    itemData[DDLogHeaderKye.logHeaderKyePVer] =
        DDAppInfo.getInstance().buildNumber;
    itemData[DDLogHeaderKye.logHeaderKyeLanId] = launcherId;
    itemData[DDLogHeaderKye.logHeaderKyeSecId] = serialId++;
    itemData[DDLogHeaderKye.logHeaderKyesysLan] =
        DDAppInfo.getInstance().localLanguageCode;
    itemData[DDLogHeaderKye.logHeaderKyeCountry] =
        Get.find<DDUserService>().authModel.userinfo?.country ?? '';
    itemData["tm"] = DateTime.now().millisecondsSinceEpoch;
    return itemData;
  }

  void putLog(DDLogType logType, Map<String, dynamic>? event) {
    if (logType.logType.isEmpty ||
        logType.subType.isEmpty ||
        logType.behavior.isEmpty ||
        event == null ||
        event.isEmpty) {
      return;
    }
    Map<String, dynamic> itemData =
        logEventData(logType.logType, logType.subType, logType.behavior, event);
    cacheList.insert(0, itemData);
    sendDelayed();
  }

  void sendDelayed() {
    if (isWaitingForSend) {
      return;
    }
    isWaitingForSend = true;
    Timer(const Duration(milliseconds: 2000), () {
      isWaitingForSend = false;
      sendLog(false);
    });
  }

  void sendLog(bool forceUploadAll) {
    try {
      List<Map<String, dynamic>> sendList = [];
      if (cacheList.isEmpty) {
        return;
      } else if (cacheList.length >= limitSize && !forceUploadAll) {
        sendList.addAll(cacheList.sublist(0, limitSize));
        cacheList.removeRange(0, limitSize);
      } else {
        sendList.addAll(cacheList);
        cacheList.clear();
      }
      doUpload(sendList, true);
    } catch (e) {}
  }

  void putLogRightNow(DDLogType logType, Map<String, dynamic>? event) {
    if (logType.logType.isEmpty ||
        logType.subType.isEmpty ||
        logType.behavior.isEmpty ||
        event == null ||
        event.isEmpty) {
      return;
    }
    Map<String, dynamic> itemData =
        logEventData(logType.logType, logType.subType, logType.behavior, event);
    List<Map<String, dynamic>> list = [];
    list.add(itemData);

    doUpload(list, false);
  }

  Future<void> doUpload(
      List<Map<String, dynamic>> sendList, bool isContinue) async {
    sendLogEvent(sendList);
  }
}

enum DDLogType {
  globalBehavior('event', 'global_behavior', 'event'),
  clickEvent("event", "click", "event");

  final String logType;
  final String subType;
  final String behavior;

  const DDLogType(this.logType, this.subType, this.behavior);
}
